#include "StdAfx.h"
#include "Message.h"
#include <math.h>
#include <stdlib.h>


void            
CMessage::CreateRandom(uint32_t size)
{    
    ResizeMessage(size);
    for(uint32_t i=0;i<size;i++){
        double num = gRNG.rand_closed01() * 2;
        int coin = (int)num;        
        mBoolMessage[i] = coin ? true : false;
    }
    mMessageSize = size;
    UpdateDoubleMessage();    
}

void
CMessage::ResizeMessage(uint32_t size)
{
    if(size>mMaxMessageSize)
    {
        //reallocate        
        bool* new_msg = new bool[(size/ChunkSize + 1)*ChunkSize];        
        if(new_msg==NULL){
            return;
        }else{            
            //copy it
            for(uint32_t i=0;i<mMessageSize;i++){
                new_msg[i] = mBoolMessage[i];
            }
            if (mBoolMessage!=NULL){
                delete mBoolMessage;
            }            
            mBoolMessage = new_msg;
			mMaxMessageSize = (size/ChunkSize + 1)*ChunkSize;
        }
    }    
}
    
void
CMessage::Append(bool* message, uint32_t size)
{
    ResizeMessage(mMessageSize+size);
    for(uint32_t i = 0;i<size;i++){
        mBoolMessage[mMessageSize++] = message[i];
    }
    UpdateDoubleMessage();
}

void            
CMessage::Replace(bool* message, uint32_t size)
{
    ResizeMessage(size);
	if(mDoubleMessage==NULL){
		mDoubleMessage = new double[mMaxMessageSize];
		if(mDoubleMessage==NULL)
			return;
	}
    for(uint32_t i = 0;i<size;i++){
        mBoolMessage[i] = message[i];		
		mDoubleMessage[i] = message[i] ? 1 : -1;
    }
    mMessageSize = size; 
}

void            
CMessage::Replace(double* message, uint32_t size)
{
    ResizeMessage(size);
    for(uint32_t i = 0;i<size;i++){
		mDoubleNoisyMessage[i] = message[i];
    }
    mMessageSize = size; 
}

void            
CMessage::Puncture(uint32_t start, uint32_t rate)
{    
    for(uint32_t i = 0;i<mMessageSize-start;i++){
        if(!(i % rate)){
            mDoubleNoisyMessage[i+start] = 0;
        }
    }    
}

double 
CMessage::Gaussian()
{
  double rndm, u1, u2, s, noise;
    do {
        rndm = gRNG.rand_closed01();
        u1 = rndm * 2 - 1.0;
        rndm = gRNG.rand_closed01();
        u2 = rndm * 2 - 1.0;
        s = u1 * u1 + u2 * u2;
      } while( s >= 1 );
    noise = u1 * sqrt( (-2.0*log(s))/s );
  return(noise*mSigma);
}

void
CMessage::UpdateDoubleMessage()
{
    if(mDoubleMessage!=NULL){
        delete mDoubleMessage;
    }
	if(mDoubleNoisyMessage!=NULL){
        delete mDoubleNoisyMessage;
    }
    
    mDoubleMessage = new double[mMessageSize];
	mDoubleNoisyMessage = new double[mMessageSize];
    if(mDoubleMessage!=NULL){
        for(uint32_t i=0;i<mMessageSize;i++){
            mDoubleMessage[i] = mBoolMessage[i] ? 1. : -1.;
            //mDoubleNoisyMessage[i] = mDoubleMessage[i] + Gaussian(); //adds gaussian noise to sample                        
			mDoubleNoisyMessage[i] = mDoubleMessage[i] + gRNG.normal(0,mSigma);
        }
    }
}
void
CMessage::Copy(CMessage* source)
{	
	mSigma = source->mSigma;
	mMessageSize = source->mMessageSize;
	mMaxMessageSize = source->mMaxMessageSize;

	//replaces actual message memory
	if(mBoolMessage!=NULL){
		delete mBoolMessage;
	}
	mBoolMessage = new bool[mMaxMessageSize];

	if(mDoubleMessage!=NULL){
		delete mDoubleMessage;
	}
	mDoubleMessage = new double[mMaxMessageSize];

	if(mDoubleNoisyMessage!=NULL){
		delete mDoubleNoisyMessage;
	}
	mDoubleNoisyMessage = new double[mMaxMessageSize];

	for(uint32_t i=0;i<mMessageSize;i++){
		mBoolMessage[i] = source->mBoolMessage[i];
		mDoubleMessage[i] = source->mDoubleMessage[i];
		mDoubleNoisyMessage[i] = source->mDoubleNoisyMessage[i];
	}
	
	//memcpy(mDoubleMessage,source.mDoubleMessage,sizeof(double)*mMessageSize);
	//memcpy(mDoubleNoisyMessage,source.mDoubleNoisyMessage,sizeof(double)*mMessageSize);	
}

uint32_t
CMessage::Compare(CMessage* msg){
	if(mMessageSize != msg->mMessageSize){
		return 0xFFFFFFFF;
	}
	uint32_t errors = 0;
	bool* m1 = msg->GetBoolMessage();	
	for(uint32_t i=0;i<mMessageSize;i++){
		if(m1[i]!=mBoolMessage[i]){
			errors ++;			
		}
	}
	return errors;
}

uint32_t
CMessage::Compare(CMessage* msg, bool debug){
	if(mMessageSize != msg->mMessageSize){
		return 0xFFFFFFFF;
	}
	uint32_t errors = 0;
	bool* m1 = msg->GetBoolMessage();	
	for(uint32_t i=0;i<mMessageSize;i++){
		if(m1[i]!=mBoolMessage[i]){
			errors ++;			
			if(debug)
				printf("\n%d",i);
		}
	}
	return errors;
}